using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Pyramid
{
    public class StructureTransfer
    {
        public GImage FineImage;
        public GImage CoarseImage;
        public GImage NewImage;
        public int NeighborhoodSize;
        public Multiresolution MR;
        private Statistics MySt;
        public StructureTransfer()
        {
            MySt=new Statistics();
            
        }
        private void init()
        {
            //make the fine image as small as the coarse one
            ImageWithDetail tempfine = new ImageWithDetail(FineImage);
            ImageWithDetail tempcoarse = new ImageWithDetail(CoarseImage);
            while (tempfine.TheImage.Width != tempcoarse.TheImage.Width && tempfine.TheImage.Height != tempcoarse.TheImage.Height)
            {
                tempfine = MR.DownSample(tempfine);
            }
            FineImage = tempfine.TheImage;
        }
        public Boolean Transfer()
        {
            int i, j;
            int[] center=new int[2];
            
            Boolean success = true;
            //make the fine image as small as the coarse one
            init();
            NewImage = new GImage(CoarseImage.Width, CoarseImage.Height);
            //march both images pixel by pixel
            for(i=0;i<FineImage.Width;i++)
                for (j = 0; j < FineImage.Height; j++)
                {
                    List<double[]> FNeighborhood = new List<double[]>();
                    List<double[]> CNeighborhood = new List<double[]>();
                    center[0]=i;center[1]=j;
                    FNeighborhood = FineImage.FindNeighborhood( center, NeighborhoodSize);
                    CNeighborhood = CoarseImage.FindNeighborhood( center, NeighborhoodSize);
                    double[] v = FindNewValue(FNeighborhood, CNeighborhood);
                    
                  
                    NewImage.SetPixel(i, j, v);
                }
            return success;
        }
     
        private double[] FindNewValue(List<double[]> FineNeighborhood, List<double[]> CoarseNeighborhood)
        {
            int i;
            double[] z,v;
            //1- build gaussian models for fine image neighborhood
            double[] ms = MySt.FindMean(FineNeighborhood);
            double[] vs = MySt.FindVariance(FineNeighborhood);

            //2- build gaussian models for coarse image neighborhood
            double[] mc = MySt.FindMean(CoarseNeighborhood);
            double[] vc = MySt.FindVariance(CoarseNeighborhood);

            //3- Find Z score at fine image
            z = new double[ms.Length];
            for (i = 0; i < ms.Length; i++)
                if (vs[i] != 0)
                    z[i] = (FineNeighborhood[0][i] - ms[i]) / vs[i];
                else
                    z[i] = ms[i];

            //4- find a new value with identical z score
            v = new double[mc.Length];
            for (i = 0; i < mc.Length; i++)
            {
                v[i] = mc[i] + z[i] * vc[i];
                if (v[i] > 255)
                    v[i] = 255;
                if (v[i] <0)
                    v[i] = 0;
            }

            return v;
        }
    }
}
